package com.xiyuan.smartutils.client.ws;

/**
 * @author xiyuan-lgz
 */
@SuppressWarnings("AlibabaAvoidStartWithDollarAndUnderLineNaming")
public interface WebSocketConstants {
    static final byte[] _EMPTY_ = {};
    /**
     * The Constant MAX_FRAME_LENGTH_16.
     */
    static final int MAX_FRAME_LENGTH_16 = 0xFFFF;
    
    /**
     * The Constant MAX_FRAME_LENGTH_63.
     */
    static final long MAX_FRAME_LENGTH_63 = 0x7FFFFFFFFFFFFFFFL;
    
    /**
     * The Constant FIN_MASK.
     */
    static final int FIN_MASK = 1 << 7;
    
    /**
     * The Constant RSV1_MASK.
     */
    static final byte RSV1_MASK = 1 << 6;
    
    /**
     * The Constant RSV2_MASK.
     */
    static final byte RSV2_MASK = 1 << 5;
    
    /**
     * The Constant RSV3_MASK.
     */
    static final byte RSV3_MASK = 1 << 4;
    
    /**
     * The Constant OPCODE_MASK.
     */
    static final byte OPCODE_MASK = 0xF;
    
    /**
     * The Constant MASK_MASK.
     */
    static final int MASK_MASK = 1 << 7;
    
    /**
     * The Constant PAYLOAD_LEN_MASK.
     */
    static final int PAYLOAD_LEN_MASK = 0x7F;
    
    /**
     * The Enum RFC6455 Opcode.
     *
     * @author xiyuan
     */
    public static enum Opcode {
        
        /**
         * The CONTINUATION. packet
         */
        CONTINUATION(0x0),
        /**
         * The Text packet.
         */
        TEXT(0x1),
        /**
         * The BINARY_FRAME.
         */
        BINARY(0x2),
        // 0x3-7 reserved
        /**
         * The CONNECTION_CLOSE.
         */
        CLOSE(0x8),
        /**
         * The PING.
         */
        PING(0x9),
        /**
         * The PONG.
         */
        PONG(0xA);
        // 0xB-F reserved
        
        /**
         * The opcode.
         */
        private final int opcode;
        
        /**
         * Instantiates a new opcode.
         *
         * @param opcode the opcode
         */
        private Opcode(int opcode) {
            this.opcode = opcode;
        }
        
        /**
         * Int value.
         *
         * @return the int
         */
        public int intValue() {
            return opcode;
        }
        
        /**
         * Value of.
         *
         * @param opc the opc
         * @return the opcode
         */
        public static Opcode valueOf(int opc) {
            switch (opc) {
                case 0x0:
                    return CONTINUATION;
                case 0x1:
                    return TEXT;
                case 0x2:
                    return BINARY;
                case 0x8:
                    return CLOSE;
                case 0x9:
                    return PING;
                case 0xA:
                    return PONG;
                default:
                    return null;
            }
        }
    }
    
    /**
     * The Enum Fin. The class description.
     *
     * @author xiyuan 2022-21-07 @version 1.0.0 新建或整理
     */
    public enum Fin {
        
        /**
         * The MORE_FRAME.
         */
        MORE_FRAME(0),
        /**
         * The FINAL.
         */
        FINAL_FRAME(1);
        
        /**
         * The fin.
         */
        private final int fin;
        
        /**
         * Instantiates a new fin.
         *
         * @param fin the fin
         */
        private Fin(int fin) {
            this.fin = fin;
        }
        
        /**
         * Int value.
         *
         * @return the int
         */
        public int intValue() {
            return fin;
        }
    }
    
    /**
     * The Enum Rsv
     *
     * @author xiyuan 2022-21-07 @version 1.0.0 新建或整理
     */
    public enum Rsv {
        
        /**
         * The RESERVE.
         */
        RESERVE(0);
        
        /**
         * The rsv.
         */
        private final int rsv;
        
        /**
         * Instantiates a new rsv.
         *
         * @param rsv the rsv
         */
        private Rsv(int rsv) {
            this.rsv = rsv;
        }
        
        /**
         * Int value.
         *
         * @return the int
         */
        public int intValue() {
            return rsv;
        }
    }
    
    /**
     * The Enum PayloadLengthType.
     *
     * @author xiyuan
     */
    public enum PayloadLengthType {
        
        /**
         * The LEN_SHORT.  0x00 - 0x7D
         */
        LEN_SHORT((byte) 0x7D, 0),
        /**
         * The LEN_16.  0x0000 - 0xFFFF
         */
        LEN_16((byte) 0x7E, 2), 
        /**
         * The LEN_63. 0x0000000000000000 - 0x7FFFFFFFFFFFFFFF
         */
        LEN_63((byte) 0x7F, 8);
        
        /**
         * The payload length type.
         */
        private final byte payloadLengthType;
        
        /**
         * The offset.
         */
        private final int offset;
        
        /**
         * Instantiates a new payload length type.
         *
         * @param payloadLengthType the payload length type
         * @param offset            the offset
         */
        private PayloadLengthType(byte payloadLengthType, int offset) {
            this.payloadLengthType = payloadLengthType;
            this.offset = offset;
        }
        
        /**
         * Byte value.
         *
         * @return the byte
         */
        public byte byteValue() {
            return payloadLengthType;
        }
        
        /**
         * Offset.
         *
         * @return the int
         */
        public int offset() {
            return offset;
        }
        
        /**
         * Value of.
         *
         * @param plt the plt
         * @return the payload length type
         */
        public static PayloadLengthType valueOf(byte plt) {
            switch (plt) {
                case 0x7E:
                    return LEN_16;
                case 0x7F:
                    return LEN_63;
            }
            if (0 <= plt && plt <= 0x7D) {return LEN_SHORT;}
            return null;
        }
        
        /**
         * Value of.
         *
         * @param payloadLength the payload length
         * @return the payload length type
         */
        public static PayloadLengthType valueOf(long payloadLength) {
            if (payloadLength <= PayloadLengthType.LEN_SHORT.byteValue()) {return PayloadLengthType.LEN_SHORT;}
            else if (payloadLength <= MAX_FRAME_LENGTH_16) {return PayloadLengthType.LEN_16;}
            else if (payloadLength <= MAX_FRAME_LENGTH_63) {return PayloadLengthType.LEN_63;}
            else {throw new IllegalArgumentException("Overflow payload length. payloadLength: " + payloadLength);}
        }
        
    }
    
}
